﻿using System;
using System.Runtime.CompilerServices;
using KinonekoSoftware.CodariaDB.Runtimes;
using KinonekoSoftware.UI;

namespace KinonekoSoftware.Studio.Components
{
    public partial class InstancePickerViewModel : SelectionDialog<InstanceCache>
    {
        internal const string Key_Instance = "data";
        internal const string Key_IsMultiple = "mode";


        private static InstanceCacheEngine _Engine;


        //-------------------------------------------------------------
        //
        //          Contracts
        //
        //-------------------------------------------------------------

        public static Task<Result<IList<InstanceCache>>> Multiple(InstanceType type)
        {
            //
            //
            _Engine ??= Platform.GetEngine<InstanceCacheEngine>();


            var instances = _Engine.Get(type).ToList();
            var context = new DialogContext();

            //
            //
            context.Set(ContextBase.Key_Value, instances);
            context.Set(Key_IsMultiple, true);

            //
            //
            return Dialog<IList<InstanceCache>>(new InstancePickerViewModel(), context);
        }

        public static Task<Result<IList<InstanceCache>>> Multiple(IEnumerable<InstanceType> type, ISet<string> idPool)
        {
            //
            //
            _Engine ??= Platform.GetEngine<InstanceCacheEngine>();
            var filter = _Engine.Get(type, idPool);
            var instances = filter.ToList();
            var context = new DialogContext();

            //
            //
            context.Set(ContextBase.Key_Value, instances);
            context.Set(Key_IsMultiple, true);

            //
            //
            return Dialog<IList<InstanceCache>>(new InstancePickerViewModel(), context);
        }

        public static Task<Result<IList<InstanceCache>>> Multiple(InstanceType type, ISet<string> idPool)
        {
            //
            //
            _Engine ??= Platform.GetEngine<InstanceCacheEngine>();

            var filter = _Engine.Get(type).Where(x => !idPool.Contains(x.Id));
            var instances = filter.ToList();
            var context = new DialogContext();

            //
            //
            context.Set(ContextBase.Key_Value, instances);
            context.Set(Key_IsMultiple, true);

            //
            //
            return Dialog<IList<InstanceCache>>(new InstancePickerViewModel(), context);
        }

        public static Task<Result<IList<InstanceCache>>> Multiple(InstanceType type, ISet<string> idPool,
            Predicate<InstanceCache> filter)
        {
            //
            //
            _Engine ??= Platform.GetEngine<InstanceCacheEngine>();

            var filter2 = _Engine.Get(type).Where(x => !idPool.Contains(x.Id)).Where(x => filter(x));
            var instances = filter2.ToList();
            var context = new DialogContext();

            //
            //
            context.Set(ContextBase.Key_Value, instances);
            context.Set(Key_IsMultiple, true);

            //
            //
            return Dialog<IList<InstanceCache>>(new InstancePickerViewModel(), context);
        }

        public static async Task<Result<InstanceCache>> SingleOf(InstanceType type)
        {
            //
            //
            _Engine ??= Platform.GetEngine<InstanceCacheEngine>();

            var instances = _Engine.Get(type).ToList();
            var context = new DialogContext();

            //
            //
            context.Set(ContextBase.Key_Value, instances);
            context.Set(Key_IsMultiple, false);

            //
            //
            var r = await Dialog<IList<InstanceCache>>(new InstancePickerViewModel(), context);

            if (!r.IsFinished)
            {
                return Result<InstanceCache>.Failed(CodariaSR.Text_Parameter_EmptyName);
            }

            if (r.Value?.Count == 0)
            {
                return Result<InstanceCache>.Failed(CodariaSR.Text_Parameter_EmptyName);
            }

            return Result<InstanceCache>.Success(r.Value
                .FirstOrDefault());
        }

        public static async Task<Result<InstanceCache>> SingleOf(InstanceType type, ISet<string> excludeIdSet)
        {
            //
            //
            _Engine ??= Platform.GetEngine<InstanceCacheEngine>();

            //
            //
            excludeIdSet ??= new HashSet<string>();

            var instances = _Engine.Get(type).Where(x => !excludeIdSet.Contains(x.Id)).ToList();
            var context = new DialogContext();

            //
            //
            context.Set(ContextBase.Key_Value, instances);
            context.Set(Key_IsMultiple, false);

            //
            //
            var r = await Dialog<IList<InstanceCache>>(new InstancePickerViewModel(), context);

            if (!r.IsFinished)
            {
                return Result<InstanceCache>.Failed(CodariaSR.Text_Parameter_EmptyName);
            }

            if (r.Value?.Count == 0)
            {
                return Result<InstanceCache>.Failed(CodariaSR.Text_Parameter_EmptyName);
            }

            return Result<InstanceCache>.Success(r.Value
                .FirstOrDefault());
        }


        //-------------------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------------------

        public InstancePickerViewModel()
        {
            Instances = new ObservableCollection<InstanceCache>();
        }


        //-------------------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------------------
        protected sealed override bool OnReceive(DialogContext context)
        {
            var single = context.GetBoolean(Key_IsMultiple);
            var instances = context.GetObject<List<InstanceCache>>(ContextBase.Key_Value);

            IsMultipleSelection = single;
            Instances.AddMany(instances, true);
            return false;
        }

        public bool HasItems => Instances.Count > 0;

        public ObservableCollection<InstanceCache> Instances { get; }
    }
}